﻿using Newtonsoft.Json;
using OpenCvSharp;
using PLCSharp.CoreModel.Common;
using PLCSharp.Models;
using Prism.Mvvm;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace PLCSharp.Views.Vision
{
    public class VisionFunction : BindableBase
    {
        [Key]
        public Guid ID { get; set; } = Guid.NewGuid();
        public Guid RecipeID { get; set; }

        private string _Name;
        /// <summary>
        /// Comment
        /// </summary>
        public string Name
        {
            get { return _Name; }
            set
            {
                if (_Name != value)
                {
                    Prompt = "已修改，请保存";
                }
                SetProperty(ref _Name, value);
            }
        }

        private string _Prompt;
        [NotMapped]
        /// <summary>
        /// 提示
        /// </summary>
        public string Prompt
        {
            get { return _Prompt; }
            set { SetProperty(ref _Prompt, value); }
        }

        private string _Comment;
        /// <summary>
        /// 备注
        /// </summary>
        public string Comment

        {
            get { return _Comment; }
            set
            {
                if (_Comment != value)
                {
                    Prompt = "已修改，请保存";
                }
                SetProperty(ref _Comment, value);
            }
        }


        [Column("Params")]
        public string SerializedParams
        {
            get => JsonConvert.SerializeObject(Params); // 自动序列化
            set => Params = JsonConvert.DeserializeObject<VisionParams>(value); // 自动反序列化

        }
        [NotMapped]
        public Mat Src { get; set; }
        private VisionParams _Params = new();
        [NotMapped]
        /// <summary>
        /// 
        /// </summary>
        public VisionParams Params
        {
            get { return _Params; }
            set { SetProperty(ref _Params, value); }
        }
        private ObservableCollection<VisionFlow> _VisionFlows = [];
        [NotMapped]
        /// <summary>
        /// 
        /// </summary>
        public ObservableCollection<VisionFlow> VisionFlows
        {
            get { return _VisionFlows; }
            set
            {
                if (value == null) return;

                SetProperty(ref _VisionFlows, value);
            }
        }

        [Column("VisionFlows")]
        public string SerializedVisionFlows
        {
            get => JsonConvert.SerializeObject(VisionFlows); // 自动序列化
            set => VisionFlows = JsonConvert.DeserializeObject<ObservableCollection<VisionFlow>>(value); // 自动反序列化

        }

        int index = 0;
        [NotMapped]
        public FlowModel Flow { get; set; } = new();
        public bool RunAll(FlowModel flow)
        {
            switch (flow.Step)
            {
                case 0:
                    index = 0;
                    flow.Step++;

                    break;
                case 1:
                    if (VisionFlows.Count > index)
                    {

                        VisionFlows[index].Flow.Reset();
                        flow.Step++;
                    }
                    else
                    {
                        flow.Done = true;

                    }
                    break;
                case 2:
                    if (RunItem(VisionFlows[index]))
                    {
                        flow.Step--;
                        index++;

                    }
                    break;


            }


            return flow.Done;

        }
        [NotMapped]
        public ObservableCollection<ImageData> ImageDatas { get; set; }

        [NotMapped]
        public VisionsModel VisionsModel { get; set; }
        public bool RunItem(VisionFlow item)
        {
            if (item == null) return false;

            switch (item.Type)
            {
                case VisionFlowType.二值化:
                case VisionFlowType.GRAY2BGR:
                case VisionFlowType.BGR2GRAY:
                case VisionFlowType.取B通道:
                case VisionFlowType.取G通道:
                case VisionFlowType.取R通道:
                case VisionFlowType.存到图像池:
                case VisionFlowType.存到文件:
                case VisionFlowType.各通道最小值:
                case VisionFlowType.各通道最大值:
                case VisionFlowType.显示图像到主页:
                    if (Src == null)
                    {
                        throw new Exception("请先获取图片！");
                    }
                    break;
            }

            switch (item.Type)
            {
                case VisionFlowType.从图像池获取图片:
                    {
                        if (item.StringParams.TryGetValue("Image", out string imageName))
                        {
                            var imageData = ImageDatas.Where(i => i.Name == imageName).FirstOrDefault();
                            if (imageData != null)
                            {
                                Src = imageData.Mat;
                                item.Flow.Done = true;
                            }
                            else
                            {
                                throw new Exception("图像池中未找到对应图片！");
                            }

                        }
                        else
                        {

                            throw new Exception("图片读取失败！");
                        }
                    }
                    break;
                case VisionFlowType.从文件获取图片:
                    {
                        if (item.StringParams.TryGetValue("Path", out string fileName))
                        {
                            Src = Cv2.ImRead(fileName);
                            item.Flow.Done = true;
                        }
                        else
                        {

                            throw new Exception("图片读取失败！");
                        }
                    }
                    break;
                case VisionFlowType.从相机获取图片:
                    switch (item.Flow.Step)
                    {
                        case 0:
                            if (item.StringParams.TryGetValue("Camera", out string cameraName))
                            {
                                item.Camera = VisionsModel.Cameras.Where(c => c.Name == cameraName).FirstOrDefault();
                                if (item.Camera != null)
                                {
                                    item.Camera.Params.ExposureTime = item.FloatParams["ExposureTime"];
                                    item.Camera.Trig();
                                    item.Flow.Step++;

                                }
                                else
                                {

                                    throw new Exception("未找到流程配置的相机！");
                                }
                            }
                            else
                            {

                                throw new Exception("本流程未正确配置相机！");
                            }
                            break;
                        case 1:

                            if (item.Camera.WaitOne())
                            {
                                Src = item.Camera.Mat;
                                item.Flow.Done = true;
                                item.Flow.Step++;
                            }
                            break;

                    }

                    break;
                case VisionFlowType.二值化:
                    if (item.IntParams.TryGetValue("ThresholdType", out int thresholdType))
                    {
                        if (item.IntParams.TryGetValue("Threshold", out int threshold))
                        {
                            if (item.IntParams.TryGetValue("MaxValue", out int maxValue))
                            {
                                if (item.BoolParams.TryGetValue("IsOtsu", out bool isOtsu))
                                {

                                    if (item.BoolParams.TryGetValue("IsTriangle", out bool isTriangle))
                                    {

                                        if (Src.Channels() == 3)
                                            Src = Src.CvtColor(ColorConversionCodes.BGR2GRAY);


                                        ThresholdTypes type = (ThresholdTypes)thresholdType;

                                        if (isOtsu)
                                        {
                                            type = type | ThresholdTypes.Otsu;
                                            item.BoolParams["IsTriangle"] = false;
                                            isTriangle = false;
                                        }
                                        if (isTriangle)
                                        {
                                            type = type | ThresholdTypes.Triangle;

                                        }
                                        if (maxValue < threshold) maxValue = threshold + 1;

                                        Cv2.Threshold(Src, Src, threshold, maxValue, type);
                                    }
                                }
                            }

                        }

                    }
                    item.Flow.Done = true;
                    break;
                case VisionFlowType.GRAY2BGR:
                    item.Flow.Done = true;
                    break;
                case VisionFlowType.BGR2GRAY:
                    item.Flow.Done = true;
                    break;
                case VisionFlowType.取B通道:
                    {
                        if (Src.Channels() < 3)
                        {
                            throw new Exception("需要彩色图像！");
                        }

                        Cv2.Split(Src, out Mat[] bgr);

                        Src = bgr[0];
                        item.Flow.Done = true;
                    }
                    break;
                case VisionFlowType.取G通道:
                    {

                        if (Src.Channels() < 3)
                        {
                            throw new Exception("需要彩色图像！");
                        }

                        Cv2.Split(Src, out Mat[] bgr);

                        Src = bgr[1];
                        item.Flow.Done = true;

                    }
                    break;
                case VisionFlowType.取R通道:
                    {
                        if (Src.Channels() < 3)
                        {
                            throw new Exception("需要彩色图像！");
                        }

                        Cv2.Split(Src, out Mat[] bgr);

                        Src = bgr[2];
                        item.Flow.Done = true;

                    }
                    break;
                case VisionFlowType.存到图像池:
                    {

                        if (item.StringParams.TryGetValue("Image", out string imageName))
                        {
                            var imageData = ImageDatas.Where(i => i.Name == imageName).FirstOrDefault();
                            if (imageData != null)
                            {
                                imageData.Mat = Src;
                                item.Flow.Done = true;
                            }
                            else
                            {
                                throw new Exception("配置异常，请重新配置！");
                            }
                        }
                        else
                        {

                            throw new Exception("未配置，请重新配置！");
                        }
                    }
                    break;
                case VisionFlowType.存到文件:
                    {

                        if (item.StringParams.TryGetValue("Path", out string imageFileName))
                        {
                            if (item.StringParams.TryGetValue("DateTimePath", out string DateTimePath))
                            {
                                if (DateTimePath == "True")
                                {
                                    var path = imageFileName += $@"{DateTime.Now:D}\";

                                    if (!System.IO.Directory.Exists(path))
                                    {

                                        System.IO.Directory.CreateDirectory(path);
                                    }
                                    imageFileName = path + DateTime.Now.ToString("T").Replace(":", "_") + ".bmp";
                                }

                                else
                                {
                                    var path = imageFileName;

                                    if (!System.IO.Directory.Exists(path))
                                    {
                                        System.IO.Directory.CreateDirectory(path);
                                    }
                                    imageFileName += $@"{DateTime.Now:D}_{DateTime.Now.ToString("T").Replace(":", "_")} .bmp";

                                }
                            }
                            else
                            {
                                var path = imageFileName;

                                if (!System.IO.Directory.Exists(path))
                                {
                                    System.IO.Directory.CreateDirectory(path);
                                }
                                imageFileName += $@"{DateTime.Now:D}_{DateTime.Now.ToString("T").Replace(":", "_")} .bmp";

                            }

                            Cv2.ImWrite(imageFileName, Src);
                            item.Flow.Done = true;

                        }
                        else
                        {

                            throw new Exception("未配置，请重新配置！");
                        }
                    }
                    break;
                case VisionFlowType.各通道最小值:

                    if (Src.Channels() < 3)
                    {
                        throw new Exception("需要彩色图像！");
                    }

                    {
                        Cv2.Split(Src, out Mat[] bgr);
                        Cv2.Min(bgr[0], bgr[1], Src);
                        Cv2.Min(Src, bgr[2], Src);
                        foreach (var c in bgr)
                        {
                            c.Dispose();
                        }
                    }
                    item.Flow.Done = true;
                    break;
                case VisionFlowType.各通道最大值:
                    if (Src.Channels() < 3)
                    {
                        throw new Exception("需要彩色图像！");
                    }

                    {
                        Cv2.Split(Src, out Mat[] bgr);
                        Cv2.Max(bgr[0], bgr[1], Src);
                        Cv2.Max(Src, bgr[2], Src);

                        foreach (var c in bgr)
                        {
                            c.Dispose();
                        }
                    }
                    item.Flow.Done = true;
                    break;
                case VisionFlowType.显示图像到主页:
                    if (item.StringParams.TryGetValue("CustomControlName", out string customControlName))
                    {
                        var customControl = GlobalModel.GetCustomControl(customControlName);
                        if (customControl != null)
                        {
                            customControl.ShowMat(Src);
                            item.Flow.Done = true;
                        }



                    }
                    else
                    {

                        throw new Exception("未配置，请重新配置！");
                    }
                    break;
                default:
                    break;
            }

            return item.Flow.Done;
        }
        [NotMapped]
        public GlobalModel GlobalModel { get; set; }
    }

    public class VisionParams : BindableBase
    {

        private RectROI _ROI = new();
        /// <summary>
        /// 
        /// </summary>
        public RectROI ROI
        {
            get { return _ROI; }
            set { SetProperty(ref _ROI, value); }
        }
    }

    public class RectROI
    {
        public int LeftTopRow { get; set; }
        public int LeftTopColumn { get; set; }
        public int RightBottomRow { get; set; }
        public int RightBottomColumn { get; set; }

    }
}
